package com.theaf.core.aspect;

import com.theaf.core.annotation.LogConfig;
import com.theaf.core.service.Log;
import com.theaf.core.utils.*;
import io.swagger.annotations.ApiModelProperty;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Author:songwenke
 * @Description:切面操作
 * @Date:create in 10:48 2017/12/1
 * @Modified By:
 **/
@Aspect
@Component
public class LogRecordAspect {
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    private void actionMethod(){}
    @Pointcut("@annotation(com.theaf.core.annotation.LogConfig)")
    private void logMethod(){}//定义一个切入点

    @Around("actionMethod() && logMethod()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
        String classType = pjp.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        String methodName = pjp.getSignature().getName(); //获取方法名称
        Long t = System.currentTimeMillis();
        Log log = new Log();
        log.setAppCode(ApplicationProperties.getProperty("spring.dubbo.application.name"));
        log.setReqTime(new Date(t));
        Object object = null;
        try {
            object = pjp.proceed();//执行该方法
        }catch (Throwable e){
            log.setErrContent(e.getMessage());
        }
        log.setOpeId(LoginUtils.getUserId());
        log.setOpeName(LoginUtils.getUserName());
        log.setOpeIp(LoginUtils.getUser().getIp());
        log.setOpeTer(LoginUtils.getUser().getTerminal());
        log.setOperType(3);
        log.setUseTs(new Long((System.currentTimeMillis()-t)).intValue());
        RequestMapping requestMapping = (RequestMapping)pjp.getSignature().getDeclaringType().getAnnotation(RequestMapping.class);
        LogConfig logConfig = (LogConfig)pjp.getSignature().getDeclaringType().getAnnotation(LogConfig.class);
        log.setUrl(requestMapping.value()[0]);
        if(StringUtils.isNotEmpty(logConfig.idField())) {
            log.setDatas(json(pjp.getArgs()[logConfig.argsIndex()], logConfig.idField()));
        }
        return object;
    }

    private Map json(Object obj,String idField) throws Exception {
        Map map = new HashMap();
        if(obj.getClass().isArray()){
            List list = new ArrayList();
            for(Object i:(Object[])obj) {
                map.put(BeanUtils.getProperty(i,idField),toMap(i));
            }
        }else if(obj instanceof Collection){
            List list = new ArrayList();
            for(Object i:(Collection)obj) {
                map.put(BeanUtils.getProperty(i,idField),toMap(i));
            }
        }else {
            map.put(BeanUtils.getProperty(obj,idField),toMap(obj));
        }
        return map;
    }

    private Map toMap(Object single){
        Map map = new HashMap();
        for (Field field : single.getClass().getDeclaredFields()) {
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            String name = field.getName();
            if(apiModelProperty!=null){
                name = apiModelProperty.value();
            }
            try {
                Object p = field.get(single);
                if(p instanceof String||p instanceof Number||p instanceof Boolean){
                    map.put(name,p);
                }else if(p instanceof Date){
                    map.put(name, DateUtils.convertDateToStr((Date)p,"yyyy-MM-dd HH:mm:ss"));
                }else if(p.getClass().isArray()){
                    List list = new ArrayList();
                    for(Object i:(Object[])p) {
                        list.add(toMap(i));
                    }
                    map.put(name, list);
                }else if(p instanceof Collection){
                    List list = new ArrayList();
                    for(Object i:(Collection)p) {
                        list.add(toMap(i));
                    }
                    map.put(name, list);
                }else{
                    map.put(name,toMap(p));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
